package io.github.lhdxhl.wechatpay.utils;

import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.util.Base64;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author lsk
 * @version 2.0.0
 * @ClassName WxPaySignUtilV3.java
 * @Description TODO
 * @createTime 2022年09月09日 16:26:00
 */
public class WxPaySignUtil {

    private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

    private static final Random RANDOM = new SecureRandom();

    /**
     * V3  SHA256withRSA 签名.
     *
     * @param method       请求方法  GET  POST PUT DELETE 等
     * @param canonicalUrl 例如  https://api.mch.weixin.qq.com/v3/pay/transactions/app?version=1 ——> /v3/pay/transactions/app?version=1
     * @param timestamp    当前时间戳   因为要配置到TOKEN 中所以 签名中的要跟TOKEN 保持一致
     * @param nonceStr     随机字符串  要和TOKEN中的保持一致
     * @param body         请求体 GET 为 "" POST 为JSON
     * @param keyPair      商户API 证书解析的密钥对  实际使用的是其中的私钥
     * @return the string
     */

    public static String sign(String method, String canonicalUrl, long timestamp, String nonceStr, String body, KeyPair keyPair) throws Exception {
        String signatureStr = Stream.of(method, canonicalUrl, String.valueOf(timestamp), nonceStr, body)
                .collect(Collectors.joining("\n", "", "\n"));

        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(keyPair.getPrivate());
        sign.update(signatureStr.getBytes(StandardCharsets.UTF_8));
        return new String(Base64.getEncoder().encode(sign.sign()));
    }

    /**
     * jsapi计算签名
     *
     * @param appId
     * @param timestamp
     * @param nonceStr
     * @param prepayId
     * @param keyPair
     * @return
     * @throws Exception
     */
    public static String signForJSApi(String appId, long timestamp, String nonceStr, String prepayId, KeyPair keyPair) throws Exception {
        String signatureStr = Stream.of(appId, String.valueOf(timestamp), nonceStr, prepayId)
                .collect(Collectors.joining("\n", "", "\n"));

        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(keyPair.getPrivate());
        sign.update(signatureStr.getBytes(StandardCharsets.UTF_8));
        return new String(Base64.getEncoder().encode(sign.sign()));
    }

    /**
     * jsapi计算签名
     *
     * @param appId
     * @param timestamp
     * @param nonceStr
     * @param prepayId
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static String paySignFromJSApi(String appId, long timestamp, String nonceStr, String prepayId, PrivateKey privateKey) throws Exception {
        String signatureStr = Stream.of(appId, String.valueOf(timestamp), nonceStr, prepayId)
                .collect(Collectors.joining("\n", "", "\n"));

        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(privateKey);
        sign.update(signatureStr.getBytes(StandardCharsets.UTF_8));
        return new String(Base64.getEncoder().encode(sign.sign()));
    }


    /**
     * @Description: 获取随机字符串
     * @Author: lsk
     * @Date: 2022/9/29 20:45
     * @Return: String
     */
    public static String generateNonceStr() {
        char[] nonceChars = new char[32];
        for (int index = 0; index < nonceChars.length; ++index) {
            nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
        }
        return new String(nonceChars);
    }
}
